<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户管理系统</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <link rel="stylesheet"
        href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Noto Sans SC', sans-serif;
        }

        body {
            min-height: 100vh;
            padding: 20px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        #app {
            width: 100%;
        }

        .container {
            width: 100%;
            background: white;
            border-radius: 12px;
            box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
            overflow: hidden;
            height: 90vh;
            display: flex;
            flex-direction: column;
        }

        header {
            background: linear-gradient(90deg, #1e3c72, #2a5298);
            color: white;
            padding: 18px 30px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-shrink: 0;
        }

        .header-left h1 {
            font-weight: 600;
            font-size: 22px;
        }

        .header-left p {
            opacity: 0.85;
            margin-top: 5px;
            font-size: 13px;
            letter-spacing: 0.5px;
        }

        .header-right {
            display: flex;
            gap: 15px;
        }

        .search-box {
            position: relative;
        }

        .search-box input {
            padding: 9px 15px 9px 38px;
            border-radius: 30px;
            border: none;
            background: rgba(255, 255, 255, 0.2);
            color: white;
            width: 220px;
            transition: all 0.3s;
            font-size: 14px;
        }

        .search-box input:focus {
            outline: none;
            background: rgba(255, 255, 255, 0.3);
            width: 260px;
        }

        .search-box i {
            position: absolute;
            left: 15px;
            top: 50%;
            transform: translateY(-50%);
            color: rgba(255, 255, 255, 0.7);
            font-size: 14px;
        }

        .user-info {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .user-avatar {
            width: 36px;
            height: 36px;
            border-radius: 50%;
            background: #4a6fcb;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        }

        .table-container {
            padding: 20px;
            display: flex;
            flex-direction: column;
            flex-grow: 1;
            overflow: hidden;
        }

        .table-wrapper {
            flex-grow: 1;
            overflow-y: auto;
            border: 1px solid #e1e8f0;
            border-radius: 8px;
            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.04);
        }

        table {
            width: 100%;
            border-collapse: collapse;
            min-width: 900px;
        }

        thead {
            position: sticky;
            top: 0;
            z-index: 10;
        }

        th {
            background: #f8fafd;
            color: #4a5568;
            text-align: center;
            padding: 14px 16px;
            font-weight: 600;
            border-bottom: 2px solid #e2e8f0;
            font-size: 14px;
            position: sticky;
            top: 0;
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
        }

        td {
            padding: 12px 16px;
            border-bottom: 1px solid #edf2f7;
            color: #4a5568;
            font-size: 14px;
        }

        tr:last-child td {
            border-bottom: none;
        }

        tr {
            text-align: center;
        }

        tr:hover {
            background-color: #f8fafc;
        }

        .status-badge {
            display: inline-block;
            padding: 5px 12px;
            border-radius: 4px;
            font-size: 13px;
            font-weight: 500;
        }

        .status-active {
            background-color: #e6fffa;
            color: #0d9488;
            border: 1px solid #b2f5ea;
        }

        .status-inactive {
            background-color: #fff5f5;
            color: #e53e3e;
            border: 1px solid #fed7d7;
        }

        .action-buttons {
            display: flex;
            gap: 8px;
        }

        button {
            padding: 7px 14px;
            border-radius: 5px;
            border: none;
            cursor: pointer;
            font-weight: 500;
            transition: all 0.2s;
            font-size: 13px;
            display: inline-flex;
            align-items: center;
            gap: 5px;
        }

        .reset-btn {
            background: #edf2f7;
            color: #4a5568;
            border: 1px solid #e2e8f0;
        }

        .reset-btn:hover {
            background: #e2e8f0;
            transform: translateY(-1px);
        }

        .ban-btn {
            background: #fff5f5;
            color: #e53e3e;
            border: 1px solid #fed7d7;
        }

        .ban-btn:hover {
            background: #fed7d7;
            transform: translateY(-1px);
        }

        .unban-btn {
            background: #ebf8ff;
            color: #3182ce;
            border: 1px solid #bee3f8;
        }

        .unban-btn:hover {
            background: #bee3f8;
            transform: translateY(-1px);
        }

        .pagination-container {
            display: flex;
            justify-content: center;
            margin-top: 18px;
            padding: 12px 0;
            flex-shrink: 0;
        }

        .pagination {
            display: flex;
            gap: 6px;
            align-items: center;
        }

        .pagination button {
            min-width: 34px;
            height: 34px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            background: #f8fafc;
            border: 1px solid #e2e8f0;
            color: #4a5568;
            font-weight: 500;
        }

        .pagination button:hover {
            background: #edf2f7;
            transform: none;
        }

        .pagination button.active {
            background: #2a5298;
            color: white;
            border-color: #2a5298;
        }

        .pagination button.disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .page-ellipsis {
            padding: 0 10px;
            color: #a0aec0;
            font-size: 14px;
        }

        .page-info {
            text-align: center;
            margin-top: 12px;
            color: #718096;
            font-size: 13px;
            flex-shrink: 0;
        }

        .controls {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 16px;
            flex-shrink: 0;
        }

        .page-size-selector {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .page-size-selector select {
            padding: 7px 14px;
            border-radius: 6px;
            border: 1px solid #e2e8f0;
            background: white;
            cursor: pointer;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
            font-size: 13px;
        }

        .id-column {
            font-family: monospace;
            font-size: 14px;
            letter-spacing: 0.5px;
        }

        @media (max-width: 992px) {
            .container {
                height: 95vh;
            }

            .table-wrapper {
                overflow-x: auto;
            }
        }

        @media (max-width: 768px) {
            .controls {
                flex-direction: column;
                gap: 12px;
                align-items: flex-start;
            }

            .search-box input {
                width: 180px;
            }

            .search-box input:focus {
                width: 200px;
            }

            .header {
                flex-direction: column;
                gap: 12px;
                align-items: flex-start;
            }

            .header-right {
                flex-wrap: wrap;
            }
        }

        /* 空数据样式 */
        .empty-table {
            text-align: center;
            padding: 40px 20px;
            color: #a0aec0;
        }

        .empty-table i {
            font-size: 48px;
            opacity: 0.3;
            margin-bottom: 15px;
        }

        .empty-table p {
            font-size: 15px;
            margin-top: 10px;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="container">

            <div class="table-container">
                <!-- <div class="controls">
                    <div class="page-size-selector">
                        <span>每页显示:</span>
                        <select v-model="pageSize" @change="changePageSize">
                            <option>10</option>
                            <option selected>15</option>
                            <option>20</option>
                            <option>30</option>
                            <option>50</option>
                        </select>
                    </div>
                </div> -->

                <div class="table-wrapper">
                    <table>
                        <thead>
                            <tr>
                                <th>账号(身份证号)</th>
                                <th>身份</th>
                                <th>电子邮箱</th>
                                <th>用户实名</th>
                                <th>激活状态</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(user, index) in paginatedUsers" :key="index">
                                <td class="id-column">{{ user.identityCard }}</td>
                                <td>{{ user.role === "teacher" ? "老师" : "学生" }}</td>
                                <td>{{ user.email }}</td>
                                <td>{{ user.username }}</td>
                                <td>
                                    <span class="status-badge"
                                        :class="user.status === 'active' ? 'status-active' : 'status-inactive'">
                                        {{ user.status === "active" ? "激活" : "未激活" }}
                                    </span>
                                </td>
                                <td style="display: flex;justify-content: center;">
                                    <div class="action-buttons">
                                        <button class="reset-btn" @click="resetPassword(user.userId)">
                                            <i class="fas fa-redo"></i> 重置密码
                                        </button>
                                        <button :class="user.status === 'active' ? 'ban-btn' : 'unban-btn'"
                                            @click="operationuser(user.userId, user.status)">
                                            <i :class="user.status === 'active' ? 'fas fa-ban' : 'fas fa-unlock'"></i>
                                            {{ user.status === "active" ? "封禁" : "解封" }}
                                        </button>
                                    </div>
                                </td>
                            </tr>
                            <tr v-if="paginatedUsers.length === 0">
                                <td colspan="6" class="empty-table">
                                    <i class="fas fa-inbox"></i>
                                    <p>没有找到匹配的用户数据</p>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>

                <div class="pagination-container">
                    <div class="pagination">
                        <button @click="goToPage(1)" :disabled="currentPage === 1" title="第一页">
                            <i class="fas fa-angle-double-left"></i>
                        </button>
                        <button @click="prevPage" :disabled="currentPage === 1" title="上一页">
                            <i class="fas fa-angle-left"></i>
                        </button>

                        <!-- 显示第一页 -->
                        <button @click="goToPage(1)" :class="{active: currentPage === 1}">1</button>

                        <!-- 显示前一个省略号（如果需要） -->
                        <span class="page-ellipsis" v-if="showStartEllipsis">...</span>

                        <!-- 显示当前页附近的2页 -->
                        <template v-for="page in nearbyPages">
                            <button @click="goToPage(page)" :class="{active: currentPage === page}" :key="page">
                                {{ page }}
                            </button>
                        </template>

                        <!-- 显示后一个省略号（如果需要） -->
                        <span class="page-ellipsis" v-if="showEndEllipsis">...</span>

                        <!-- 显示最后一页 -->
                        <button v-if="totalPages > 1" @click="goToPage(totalPages)"
                            :class="{active: currentPage === totalPages}">
                            {{ totalPages }}
                        </button>

                        <button @click="nextPage" :disabled="currentPage === totalPages" title="下一页">
                            <i class="fas fa-angle-right"></i>
                        </button>
                        <button @click="goToPage(totalPages)" :disabled="currentPage === totalPages" title="最后一页">
                            <i class="fas fa-angle-double-right"></i>
                        </button>
                    </div>
                </div>

                <div class="page-info">
                    显示 {{ startIndex + 1 }} 到 {{ endIndex }} 条，共 {{ filteredUsers.length }} 条记录
                </div>
            </div>
        </div>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
                users: [],
                filteredUsers: [],
                searchQuery: '',
                currentPage: 1,
                pageSize: 15,
                totalPages: 1
            },
            computed: {
                // 分页后的用户数据
                paginatedUsers() {
                    const start = (this.currentPage - 1) * this.pageSize;
                    const end = start + this.pageSize;
                    return this.filteredUsers.slice(start, end);
                },

                // 计算当前页附近2页的页码
                nearbyPages() {
                    const pages = [];
                    const start = Math.max(2, this.currentPage - 2);
                    const end = Math.min(this.totalPages - 1, this.currentPage + 2);

                    for (let i = start; i <= end; i++) {
                        if (i > 1 && i < this.totalPages) {
                            pages.push(i);
                        }
                    }
                    return pages;
                },

                // 是否显示起始省略号
                showStartEllipsis() {
                    return this.currentPage - 2 > 2;
                },

                // 是否显示结束省略号
                showEndEllipsis() {
                    return this.currentPage + 2 < this.totalPages - 1;
                },

                // 当前页的起始索引
                startIndex() {
                    return (this.currentPage - 1) * this.pageSize;
                },

                // 当前页的结束索引
                endIndex() {
                    const end = this.startIndex + this.pageSize;
                    return Math.min(end, this.filteredUsers.length);
                },

                // 总页数
                // totalPages() {
                //     return Math.ceil(this.filteredUsers.length / this.pageSize);
                // }
            },
            created() {
                this.loadUsers();
            },
            methods: {
                // 加载用户数据
                loadUsers() {
                    axios.post("http://localhost:8081/admin/selectAllUser")
                        .then((res) => {
                            console.log(res)
                            this.users = res.data
                            this.filteredUsers = res.data;
                            this.totalPages = Math.ceil(this.filteredUsers.length / this.pageSize);
                        })
                        .catch((error) => {
                            alert("服务器内部错误，请稍后再试");
                        });
                },


                // 更改每页显示数量
                changePageSize() {
                    this.currentPage = 1;
                    this.totalPages = Math.ceil(this.filteredUsers.length / this.pageSize);
                },

                // 前往上一页
                prevPage() {
                    if (this.currentPage > 1) {
                        this.currentPage--;
                    }
                },

                // 前往下一页
                nextPage() {
                    if (this.currentPage < this.totalPages) {
                        this.currentPage++;
                    }
                },

                // 跳转到指定页
                goToPage(page) {
                    if (page >= 1 && page <= this.totalPages) {
                        this.currentPage = page;
                    }
                },

                // 用户操作（封禁/解封）
                operationuser(userId, status) {
                    const action = status === 'active' ? '封禁' : '解封';
                    let params = new URLSearchParams();
                    params.append('userId', userId);
                    axios.post("http://localhost:8081/admin/updateuserstate", params)
                        .then((res) => {
                            const user = this.users.find(u => u.userId === userId);
                            if (user) {
                                user.status = user.status === 'active' ? 'inactive' : 'active';
                            }
                            this.filteredUsers = [...this.users];

                            // 显示操作反馈
                            this.showNotification(`用户已${action}！`, status === 'active' ? 'error' : 'success');
                        })
                        .catch((error) => {
                            alert("服务器内部错误，请稍后再试");
                        });
                },

                // 重置密码
                resetPassword(userId) {
                    let params = new URLSearchParams();
                    params.append('userId', userId);
                    axios.post("http://localhost:8081/admin/resetpassword", params)
                        .then((res) => {
                            const user = this.users.find(u => u.userId === userId);
                            if (user) {
                                this.showNotification(`已重置 ${user.username} 的密码`, 'info');
                            }
                        })
                        .catch((error) => {
                            alert("服务器内部错误，请稍后再试");
                        });
                },

                // 显示通知
                showNotification(message, type) {
                    // 创建通知元素
                    const notification = document.createElement('div');
                    notification.className = 'notification';

                    // 根据类型设置样式
                    const styles = {
                        position: 'fixed',
                        top: '20px',
                        right: '20px',
                        padding: '14px 24px',
                        borderRadius: '6px',
                        boxShadow: '0 5px 15px rgba(0,0,0,0.15)',
                        display: 'flex',
                        alignItems: 'center',
                        gap: '12px',
                        zIndex: '1000',
                        animation: 'slideIn 0.3s',
                        opacity: '0.95'
                    };

                    if (type === 'success') {
                        styles.background = '#48bb78';
                        styles.color = 'white';
                    } else if (type === 'error') {
                        styles.background = '#e53e3e';
                        styles.color = 'white';
                    } else {
                        styles.background = '#4299e1';
                        styles.color = 'white';
                    }

                    // 应用样式
                    Object.assign(notification.style, styles);

                    // 添加图标
                    let iconClass = 'fas fa-info-circle';
                    if (type === 'success') iconClass = 'fas fa-check-circle';
                    if (type === 'error') iconClass = 'fas fa-exclamation-circle';

                    notification.innerHTML = `
                        <i class="${iconClass}" style="font-size: 20px;"></i>
                        <span>${message}</span>
                    `;

                    // 添加到页面
                    document.body.appendChild(notification);

                    // 3秒后移除
                    setTimeout(() => {
                        notification.style.animation = 'fadeOut 0.5s';
                        setTimeout(() => {
                            if (notification.parentNode) {
                                notification.parentNode.removeChild(notification);
                            }
                        }, 500);
                    }, 3000);
                }
            }
        });

        // 添加关键帧动画
        const style = document.createElement('style');
        style.innerHTML = `
            @keyframes slideIn {
                from {
                    transform: translateX(100%);
                    opacity: 0;
                }
                to {
                    transform: translateX(0);
                    opacity: 0.95;
                }
            }
            
            @keyframes fadeOut {
                from {
                    opacity: 0.95;
                }
                to {
                    opacity: 0;
                }
            }
        `;
        document.head.appendChild(style);
    </script>
</body>

</html>